; MC404 - Organizacao Basica de Computadores e Linguagem de Montagem
; Professor: Alexandro Baldassin
; Turma C
;
;  Programa em assembly (NASM) para Compactação e Descompactação LZW
;  Para Compactação e Descompactação de Arquivos  utilizando codigos de 9 a 16 bits
;
;  Plataforma alvo: arquivos objetos (OBJ/EXE) 16-bit (DOS)
;  OBS: montar com a opcao -fobj
;
; Desenvolvedores: Ng Kin Jin              RA 045565
;                  Tiago R C Falcão             RA 046802


SEGMENT code                ; segmento de codigo
..start:                    ; ponto de entrada do programa
  ; incializa dados
  mov ax,data
  mov ds,ax

  ; inicializa pilha (SS:SP)
  mov  ax, stack
  mov  ss, ax
  mov  sp, stacktop
  
  call STARTSETUP    ;Funcao de Verificacao e Configuracao Inicial do Programa
  call INICFILES     ;Funcao de Inicializacao dos Arquivos
  
  call FUNCTION      ;Funcao de Direcionamento da Execucao : Compactacao / Descompactacao
  
  call ENDFILES      ;Funcao de Finalizacao dos Arquivos

  call showdicio     ;Funcao de Impressao do Tamanho do Dicionario
  call showsizes     ;Funcao de Impressao dos Tamanhos dos Arquivos
  
  call END
  
  
;==============================================================================
;==============================================================================
;  Funcao de Configuracao Inicial de Execucao
;==============================================================================
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Verificacao e Configuracao Inicial do Programa
;Descricao:
;   Executa o Algoritmo de Compactacao LZW, utilizando as
;   configuracoes pre-determinadas
;Requer:
;   Dados de Configuracao
;   Nomes de Arquivos no PSP
;   DS setado em data
;   ES setado em PSP
;Retorna:
;   -Nada-
;Modifica:
;   Variaveis de  Configuracao
;   Variveis com Nomes dos Arquivos
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STARTSETUP:
  push ax
  push cx
  push dx
  push di
  push si
  
  ;Calcula Quantidade de Caracteres
  xor ch,ch
  mov cl,[es:0x80]
  
  ;Seta Posicoes iniciais
  mov ah,0x2D	    ;'-'
  mov si,0x82	    ;Inicio dos argumentos no PSP
  
  ;busca por '-'
  mov al,[es:si]
  cmp al,ah
  je STSETCONF
  
  ;'-' Nao encontrado, sair com erro
  mov ah,0x09
  mov dx,UD_FUCT
  int 0x21
  jmp END

  ;Loop de configuracao da escucao
  STSETCONF:
    ;Verifica se ainda ha mais caracteres de argumento
    or cx,0x00
    jnz STSETCONFJ
      jmp STSETCONFE
    STSETCONFJ:
    ;"Anda"
    inc si
    dec cx
    ;Pega Novo Char
    mov al,[es:si]
	
    ;Espaco / Fim das Opcoes
    cmp al,0x20 
    jne STSETCONFS
	jmp STSETCONFE
    STSETCONFS:
	
    ;Tamanho do Codigo = 9
    cmp al,'9'
    jne OPT9N
      mov ah,0x9
      mov [CODSZ],ah
      jmp STSETCONF
    OPT9N:
	
    ;Tamanho do Codigo = 10
    cmp al,'0'
    jne OPT0N
      mov ah,0xA
      mov [CODSZ],ah
      jmp STSETCONF
    OPT0N:
	
    ;Tamanho do Codigo = 11
    cmp al,'1'
    jne OPT1N
      mov ah,0xB
      mov [CODSZ],ah
      jmp STSETCONF
    OPT1N:
	
    ;Tamanho do Codigo = 12
    cmp al,'2'
    jne OPT2N
      mov ah,0xC
      mov [CODSZ],ah
      jmp STSETCONF
    OPT2N:
    
    ;Tamanho do Codigo = 13
    cmp al,'3'
    jne OPT3N
      mov ah,0xD
      mov [CODSZ],ah
      jmp STSETCONF
    OPT3N:
    
    ;Tamanho do Codigo = 14
    cmp al,'4'
    jne OPT4N
      mov ah,0xE
      mov [CODSZ],ah
      jmp STSETCONF
    OPT4N:
    
    ;Tamanho do Codigo = 15
    cmp al,'5'
    jne OPT5N
      mov ah,0xF
      mov [CODSZ],ah
      jmp STSETCONF
    OPT5N:
    
    ;Tamanho do Codigo = 16
    cmp al,'6'
    jne OPT6N
      mov ah,0x10
      mov [CODSZ],ah
      jmp STSETCONF
    OPT6N:
	
    ;Transforma em minuscula
    or ax,0x20
    
    ;Ajuda
    cmp al,'h' 
    jne OPTHN
      mov ah,0x09
	  mov dx,HELP_M
	  int 0x21
	  call pause
      jmp END
    OPTHN:
    
    ;;Binaria, obrigatorio numero crescente de bits
    ;cmp al,'b' 
    ;jne OPTBN
    ;  mov ah,0x01
    ;  mov [CODSZ],ah
    ;  jmp OPTG
    ;OPTBN:
	
    ;Numero de Bits Crescentes
    cmp al,'g' 
    jne OPTGN
	  OPTG:
      mov ah,0x01
      mov [G_BITS],ah
      jmp STSETCONF
    OPTGN:
    
    ;Limpar HASH quando cheia
    cmp al,'q' 
    jne OPTQN
      mov ah,0x01
      mov [C_DICTIO],ah
      jmp STSETCONF
    OPTQN:

    ;Compacta
    cmp al,'e' 
    jne OPTEN
      mov ah,0x01
      mov [MOD],ah
      jmp STSETCONF
    OPTEN:
    
    ;Descompacta
    cmp al,'x'
    jne OPTXN
      mov ah,0x02
      mov [MOD],ah
      jmp STSETCONF
    OPTXN:
    
    ;Modo Forcado
    cmp al,'f' 
    jne OPTFN
      xor ah,ah
      mov [FORCE],ah
      jmp STSETCONF
    OPTFN:
    
    ;Modo Exibicao da Quantidade de Itens no dicionario
    cmp al,'d' 
    jne OPTDN
      or ah,0x01
      mov [S_DICIO],ah
      jmp STSETCONF
    OPTDN:
    
    ;Modo Exibicao de Tamanho de arquivos
    cmp al,'s' 
    jne OPTSN
      or ah,0x01
      mov [SHOWSZ],ah
      jmp STSETCONF
    OPTSN:
    
    ;Modo Exibicao do numero de colisoes
    cmp al,'c' 
    jne OPTCN
      or ah,0x01
      mov [SHOWCOL],ah
      jmp STSETCONF
    OPTCN:
    
    ;Descompacta Exibindo Arquivo Descomapctado na Tela
    cmp al,'v' 
    jne OPTVN
      or ah,0x01
      mov [V_OFL],ah
      jmp STSETCONF
    OPTVN:
    
    ;Sem Impressao de "LZW" no compactado
    cmp al,'t' 
    jne OPTTN
      or ah,0x01
      mov [P_LZW],ah
      jmp STSETCONF
    OPTTN:
    
    ;Sem impressao do Bit de configuracao
    cmp al,'y' 
    jne OPTYN
      or ah,0x01
      mov [B_CONF],ah
      jmp STSETCONF
    OPTYN:
	
	;Opcao Desconhecida
	mov dl,al
	mov ah,0x02
	int 0x21
	mov ah,0x09
	mov dx,OPT_NF
	int 0x21
	jmp STSETCONF

  STSETCONFE:

  ;Testes Para ver se foi definido modo de execucao
  mov al,[MOD]
  or al,0x00
  jnz STSETCP
    mov ah,0x09
    mov dx,UD_FUCT
    int 0x21
    jmp END
  STSETCP:

  ;Calcula Valor de AND limitador das STRs
  mov ah,[CODSZ]
  mov dx,0x01
  call SHIFTL
  dec dx
  mov [AND_STR],dx
  
  ;Seta detalhes para copia do nome do arquivo 1
  jcxz SSCPY1E
  inc si
  dec cx
  mov di,FL_NAME1
  xor ah,ah

  ;Copia nome do Arquivo 1
  call STRCPY

  ;Testa Copia do Nome do Arquivo 1
  or ax,0x000
  jnz SSCPY1
  SSCPY1E:
    mov ah,0x09
    mov dx,IO_FL_NF
    int 0x21
    jmp END
  SSCPY1:
  
  ;Seta detalhes para copia do nome do arquivo 2
  jcxz SSCPY2E
  inc si
  dec cx
  mov di,FL_NAME2
  
  ;Copia nome do Arquivo 2
  call STRCPY
  
  ;Testa Copia do Nome do Arquivo 2
  or ax,0x000
  jnz SSCPY2
  SSCPY2E:
    mov ah,0x09
    mov dx,O_FL_NF
    int 0x21
    jmp END
  SSCPY2:

  pop si
  pop di
  pop dx
  pop cx
  pop ax
  ret
;==============================================================================
;  Funcoes de Abertura/Criacao/Fechamento de Arquivos
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Inicializacao dos Arquivos
;Descricao:
;   Abre o Arquivo de Entrada e Cria o de Saida respeitando
;   as configuracoes de sobreescrita
;   Em caso de Algum erro sai da execucao com a devida
;   mensagem de erro
;Requer:
;   Nome do Arquivo de Entrada na variavel "FL_NAME1"
;   Nome do Arquivo de Saida na variavel "FL_NAME2"
;Retorna:
;   -Nada-
;Modifica:
;   Variavel de File Handle da Entrada "FL_HANDLE1"
;   Variavel de File Handle da Saida "FL_HANDLE2"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INICFILES:
  push ax
  push bx
  push cx
  push dx
  push si

  ;Arquivo 1

  ;Comando de Abertura de Arquivo
  mov ah,0x3d
  xor al,al
  
  ;Seta Inicio de String
  mov dx,FL_NAME1
  
  ;Abre!
  int 0x21
  
  ;Verificacao de Erro na Abertura
  jnc OK_OPEN 
  call OPENERRO
  jmp END
  OK_OPEN:

  ;Salva o File Handle
  mov [FL_HANDLE1],ax

  ;Arquivo 2
  
  ;Seta Inicio de String
  mov dx,FL_NAME2
  
  ;Forca sobreescrita?
  xor ch,ch
  mov cl,[FORCE]
  jcxz OVERCRFL
    ;Testa se Arquivo ja existe e cancela execucao, com erro
    ;Tenta Abrir Arquivo
    mov ah,0x3d
    mov al,0x00
    int 0x21
    mov bx,ax
    ;Testa Abertura, em caso de Erro, segue execucao com
    ; criacao do arquivo
    jnc OVERCRFLERRO
    cmp al,0x02
    je OVERCRFL
    cmp al,0x03
    je OVERCRFL
    jmp OVERCRFLERRO2
    OVERCRFLERRO:   ;Arquivo Existe!
      ;Fecha Arquivo
      mov ah,0x3e
      int 0x21
    OVERCRFLERRO2:  ;Arquivo Existe!
      ;Coloca $ no final do Nome do Arquivo
      mov si,dx
      dec si
      OVERCRFLERROP:
	inc si
	mov cl,[si]
	or cl,0x00
	jnz OVERCRFLERROP
      mov [si],byte 0x20 ;Espaco
      inc si
      mov [si],byte 0x24 ; $
      ;Imprime Nome do Arquivo
      mov ah,0x09
      int 0x21
      ;Imprime Mensagem de Erro
      mov dx,FL_EXIST
      int 0x21
      ;Fecha Arquivo de Entrada 
      mov ah,0x3e
      mov bx,[FL_HANDLE1]
      int 0x21
      ;Finaliza
      jmp END
      
  OVERCRFL:
  
  ;Cria Arquivo
  mov ah,0x3C
  xor cx,cx
  int 0x21

  ;Testa Criacao de Arquivo
  jnc CRFLOUTOK
	call OPENERRO
    ;Fecha Arquivo de Entrada
    mov ah,0x3e
    mov bx,[FL_HANDLE1]
    int 0x21
    jmp END
  CRFLOUTOK:

  ;Salva File Handle
  mov [FL_HANDLE2],ax
  
  pop si
  pop dx
  pop cx
  pop bx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Finalizacao dos Arquivos
;Descricao:
;   Fecha o Arquivo de Entrada e o de Saida
;Requer:
;   Variavel de File Handle da Entrada "FL_HANDLE1"
;   Variavel de File Handle da Saida "FL_HANDLE2"
;Retorna:
;   -Nada-
;Modifica:
;   Fecha Arquivo de Entrada Invalidando "FL_HANDLE1"
;   Fecha Arquivo de Saida Invalidando "FL_HANDLE2"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ENDFILES:
  push ax
  push bx
  
  ;fecha Arquivo de Entrada
  mov ah,0x3e
  mov bx,[FL_HANDLE1]
  int 0x21
  ;Finaliza Escritas no Arquivo de Saida
  call fwriteclean
  call fputcclean
  ;Fecha Arquivo de Saida
  mov bx,[FL_HANDLE2]
  int 0x21
  
  pop ax
  pop bx
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Impressao da Devida Mensagem de Erro na Abertura /Criacao
;Descricao:
;   Imprime Nome do Arquivo no qual houve o problema, com
;     descricao do erro
;Requer:
;   AL retornado por interrupcao de abertura
;   DX setado com end da string do nome do arquivo no qual
;     houve o erro, padrao igual aa interrupcao de abertura
;Retorna:
;   -Nada-Finaliza
;Modifica:
;   String com Nome do Arquivo no qual houve o erro
;     é concatenado " $"no final deste.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OPENERRO:
;Exibicao das Mensagens de erro para a abertura de arquivo
  push ax
  push cx
  push si
  push dx

  ;Coloca $ no final do nome do arquivo
  mov si,dx
  dec si
  OPERFLNM:
    inc si
    mov cl,[si]
    or cl,0x00
    jnz OPERFLNM
  mov [si],byte 0x20 ;Espaco
  inc si
  mov [si],byte 0x24 ; $
  mov cx,ax
  
  ;Imprime Nome
  mov ah,0x09
  int 0x21

  ;Testa Erro de Arquivo Nao Encontrado
  cmp cl,0x02
  jne E_FILE_NF
    mov dx,FILE_NF
    jmp EXE_ERRO
  E_FILE_NF:
  ;Testa Erro de Path Nao Encontrado
  cmp cl,0x03
  jne E_PATH_NF
    mov dx,PATH_NF
    jmp EXE_ERRO
  E_PATH_NF:
  ;Testa Erro de Falta de File Handle
  cmp cl,0x04
  jne E_NHAN_AV
    mov dx,NHAN_AV
    jmp EXE_ERRO
  E_NHAN_AV:
  ;Testa Erro de Acesso Proibido
  cmp cl,0x05
  jne E_ACCE_DE
    mov dx,ACCE_DE
    jmp EXE_ERRO
  E_ACCE_DE:
  ;Testa Erro de Modo de Abertura Invalido
  cmp cl,0x0C
  jne E_MODE_IN
    mov dx,MODE_IN
    jmp EXE_ERRO
  E_MODE_IN:
  ;Erro desconhecido
  mov dx,ERROR_NR
  
  EXE_ERRO:
    ;Imprime String de Erro na Tela
    int 0x21
    ;Finaliza
    pop dx
    pop si
    pop cx
    pop ax
    ret
;==============================================================================
;  Funcoes de Escrita e Carregamento do Byte de Configuracao
;==============================================================================
;******************************************************************************
; *Sobre Byte de Configuracao:
; *       7     6      5     4      3      2       1       0
; *    | BF | CF | GF | XX | NB | NB | NB | NB |
; *    BF = Byte Flag = Sempre igual a 1 para determinacao de Byte de Configuracao
; *   CF = Clean Flag = Determina se o Dicionario sera Limpo Quando Cheio
; *    GF = Grow Flag = Determina se o Numero de Bits sera crescente ou estatico
; *    NB = Numero de Bits Iniciais da Codificacao, de 0~15
; *              (Este Programa so consegue processar 1;9~15;0 (0 representa 16))
;******************************************************************************
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Escrita do Byte de Configuracao no Arquivo Compactado
;Descricao:
;   Formata um Byte com dados da configuracao da compactacao para
;     processar a descompactacao de forma perfeita, e escreve este byte
;     no arquivo compactado
;Requer:
;   Configuracoes:
;      B_CONF      Caso != 0 Nao Escreve Byte de Configuracao
;      CODSZ        Numero de Bits do Codigo Gerado
;      G_BITS       Se != 0 o numero de bits ira crescer durante execucao
;      C_DICTIO      Se != o dicionario podera ser limpo durante execucao
;Retorna:
;   -Nada-
;Modifica:
;   Arquivo de Saida com Byte de Configuracao caso B_CONF=0 [default]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PRT_BYTE_CONFIG:
	push dx
	mov dh,[B_CONF]
	or dh,0x00
	jnz PRTBITCN
		mov dl,[CODSZ];Tamanho de Codigo
		and dl,0x0F
		
		mov dh,[G_BITS];Numero crescente de bits
		shl dh,5
		or dl,dh
		
		mov dh,[C_DICTIO];Numero crescente de bits
		shl dh,6
		or dl,dh
		
		or dl,0x80     ;Indicador de Bit de Configuracao
		
		call fputc
	PRTBITCN:
	pop dx
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Analise do Byte de Configuracao
;Descricao:
;   Testa Byte de configuracao do arquivo compactado e
;     Carrega a configuracao baseada nele
;Requer:
;   B_CONF
;Retorna:
;   -Nada-
;Modifica:
;   Configuracao da Execucao:
;      CODSZ        Numero de Bits do Codigo Gerado
;      AND_STR    Valor de AND para Codificacao gerado a partir de CODSZ
;      G_BITS       Se != 0 o numero de bits ira crescer durante execucao
;      C_DICTIO      Se != o dicionario podera ser limpo durante execucao
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
LOAD_BYTE_CONFIG:
    push ax
	push dx
	
	mov dh,[B_CONF]
	or dh,0x00
	jnz LOADBITCN
		call fgetc
		
		mov dh,0x80;Verifica se eh um bit de configuracao
		and dh,dl
		jnz LOADBITCNEX
		  ;Imprime Mensagem de Erro
		  mov dx,BITC_NF
		  mov ah,0x09
		  int 0x21
		  ;Finaliza Execucao
          call ENDFILES
	      jmp END
		LOADBITCNEX:
		
		;Tamanho de Codigo
		mov dh,0x0F
		and dh,dl
		jnz LOADBITCSZ
		  or dh,0x10
		LOADBITCSZ:
		mov [CODSZ],dh
		
		;Avalia Tamanho de Codigo
		cmp dh,0x01
		je LOADBITCNC
		cmp dh,0x09
		jb LOADBITE
		cmp dh,0x10
		jg LOADBITE
		LOADBITCNC:
		
		;Calcula Valor de AND limitador das STRs
		mov al,dl   ;salva byte de configuracao
        mov ah,dh
        mov dx,0x01
        call SHIFTL
        dec dx
        mov [AND_STR],dx
		mov dl,al    ;recupera byte de configuracao
		
		;Numero crescente de bits
		shr dl,5
		mov dh,0x01
		and dh,dl
		mov [G_BITS],dh
		
		;Limpeza de Dicionario
		shr dl,1
		mov dh,0x01
		and dh,dl
		mov [C_DICTIO],dh
		
	LOADBITCN:
	pop dx
	pop ax
	ret

	
	;Qtd de Bits Invalida
	LOADBITE:
	  ;Imprime Quantidade de Bits Indicada no Byte
	  shr dx,8
	  call printHexn
	  ;Mensagem de Erro
	  mov dx,QTDE_BT
	  mov ah,0x09
	  int 0x21
	  ;Finaliza Programa
      call ENDFILES
	  jmp END
;==============================================================================
;  Funcoes de Compactacao e Descompactacao
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Direcionamento de Execucao
;Descricao:
;   Verifica Variveis de Configuracao e Determina a
;   Compactacao ou Descompactacao do Arquivo de Entrada
;Requer:
;   -Nada-
;Retorna:
;   -Nada-
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FUNCTION:
  push ax
  mov ah,[MOD]
  
  ;Testa modo de Execucao
  cmp ah,0x01
  jne FDESC
  jb FCOMPBIN
  FCOMPAC:
    ;Funcao Proibida para Compactacao
	xor ah,ah
	mov [V_OFL],ah
    ;Compacta
    call COMPACT
    jmp FEND
  FDESC:
    ;Descompacta
    call DESCOMPACT
    jmp FEND
  FCOMPBIN:
    ;Compacta em nivel Binario
    ;call DESCOMPACT
    ;jmp FEND
  FEND:
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Compactacao
;Descricao:
;   Executa o Algoritmo de Compactacao LZW, utilizando as
;   configuracoes pre-determinadas
;Requer:
;   -Nada-
;Retorna:
;   -Nada-
;Modifica:
;   Arquivo de Entrada (SEGBuffer,Buffer,Ponteiro de Arq)
;   Arquivo de Saida (SEGBuffer,Buffer,Ponteiro de Arq)
;   Hash/Dicionario
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COMPACT:
  push cx
  push dx
  push si
  push ax
  push bx
  push bp
  
  
  ;Escrita do do Tipo de Arquivo
  mov cl,[P_LZW]
  or cl,0x00
  jnz COMPACTSLZW
    mov cl,[LEN_FORMAT]
    mov dx,FORMAT
    call fputs
  COMPACTSLZW:

  ;Escrita do Bit de Configuracao
  call PRT_BYTE_CONFIG

  ;Leitura Inicial
  call fgetc
  jc COMPACTEND2
  
  ;Calculo Inicial
  xor dh,dh
  mov si,dx
  
  ;Constantes
  mov al,[CODSZ]
  mov ah,al
  mov bx,[FL_HANDLE2]

  COMPACTL:
    ;Leitura
    call fgetc
    jc COMPACTEND

    ;Salva na HASH
    mov cx,si
    call INSHASH

    jnc COMPHASHFE
      ;Testa se STR+CHAR foi encontrado
      cmp bp,0x0001
      je COMPACTL  ;Volta ao Loop se encontrado
	  
    COMPHASHFE:; Se foi inserido agora ou o Dicionario ta cheio
	  
      ;Salva CHAR para ser STR do proximo laco
	  xor dh,dh
      mov si,dx
	  
      ;Escrever STR
      mov dx,cx
	  mov al,ah
      call fwrite

      jmp COMPACTL

    COMPACTEND:
    ;Escrever STR final e sem CHAR
    mov dx,si
	mov al,ah
    call fwrite

  COMPACTEND2:
  call showcolnumber  ;Imprime numero de Colisoes
  pop bp
  pop bx
  pop ax
  pop si
  pop dx
  pop cx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Descompactacao
;Descricao:
;   Executa o Algoritmo de Descompactacao para LZW, 
;   utilizando as configuracoes e verificando se o arquivo
;   eh realmente um arquivo compactado LZW
;Requer:
;   -Nada-
;Retorna:
;   -Nada-
;Modifica:
;   Arquivo de Entrada (SEGBuffer,Buffer,Ponteiro de Arq)
;   Arquivo de Saida (SEGBuffer,Buffer,Ponteiro de Arq)
;   Hash(Como Vetor)/Dicionario
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DESCOMPACT:
  push dx
  push ax
  push cx
  push bp
  push bx
  
  ;Verificar LZW?
  mov dl,[P_LZW]
  or dl,0x00
  jnz DESCOMPACTDCLZW
    ;Verifica se tem LZW
	;L
    call fgetc
    cmp dl,'L'
    jne DESCOMPACTNLZW
	;Z
    call fgetc
    cmp dl,'Z'
    jne DESCOMPACTNLZW
	;W
    call fgetc
    cmp dl,'W'
    je DESCOMPACTC
    DESCOMPACTNLZW:
	  ;Nao Possui
	  ;Mensagem de erro
      mov dx,FL_LZWN
      mov ah,0x09
      int 0x21
	  ;Finaliza
      call ENDFILES
      jmp END
    DESCOMPACTC:
  DESCOMPACTDCLZW:
  
  ;Carrega bit de configuracao
  call LOAD_BYTE_CONFIG
  
  ;Inicializa Array
  call INIARRAY

  ;Numero de Bits para Leitura
  xor ah,ah
  mov al,[CODSZ]
  
  ;Le primeiro item
  call fread
  mov cx,dx    ;Salva
  
  ;Imprime primeiro item como char
  call fputc
  
  DESCOMPACTL:
	call fread        ;Le NEW_CODE
	jc DESCOMPACTE    ;Verifica Leitura
	
	;Testa se NEW_CODE eh menor que ultimo codigo adicionado no dicionario
	cmp dx,bp
	jbe DESCOMPACTLE
	  ;Nao existe no dicionario
	  mov bx,cx
      call PRINTSTRARRAY   ;Imprime OLD_CODE
	  call STR0ARRAY       ;Pega o Char 0 de OLD_CODE
	  xchg bx,dx
	  call fputc           ;Imprime Char 0
	  
	  jmp DESCOMPACTLC
	  
	DESCOMPACTLE:
	  ;Existe no dicionario
	  mov bx,dx
	  call STR0ARRAY       ;Pega o Char 0 de NEW_CODE
	  xchg bx,dx
      call PRINTSTRARRAY   ;Imprime NEW_CODE
	  
	DESCOMPACTLC:
	;Insere no Dicionario  OLD_CODE + Char 0 (OLD ou NEW)
	call INSARRAY
	;OLD_CODE=NEW_CODE
	mov cx,bx
	
	jmp DESCOMPACTL    ;Loop
  DESCOMPACTE:
  
  ;Salva tamanho do dicionario
  mov [LAST_VLE_INS],bp
  
  pop bx
  pop bp
  pop cx
  pop ax
  pop dx
  ret
;==============================================================================
;==============================================================================
;  Funcoes de Array para Descomapctacao
;==============================================================================
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Inicializacao do ARRAY
;Descricao:
;   Insere os ASCII no ARRAY vazio, sem o char NULL uma vez que este "sempre" esta no array
;Requer:
;   -Nada-
;Retorna:
;   BP - Ultimo Codigo Inserido
;Modifica:
;   ARRAY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INIARRAY:
  push cx
  push dx
  push bx
  
  ;Limpa BP
  xor bp,bp
  
  ;Primeiro ASCII a ser inserido
  mov dx,0x0001
  
  ;Quantidade a ser inserida
  mov bx,0xFF
  
  INIARRAYL:
    ;Insere
    call INSARRAY
    ;Proximo ASCII
	inc dl
	;Faz enquanto tem a inserir
	dec bx
	jnz INIARRAYL
  
  pop bx
  pop dx
  pop cx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Insercao no ARRAY
;Descricao:
;   Insere um STR+CHAR no ARRAY
;Requer:
;   CX - String
;   DL - Char
;Retorna:
;   BP - Com ultimo valor inserido
;   CF - Sucesso se =0, caso contrario =1
;Modifica:
;   ARRAY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INSARRAY:
  push ax
  push bx
  push cx
  push dx
  push es
  push di
  
  ;Posicao de Insercao Atual
  inc bp
  
  ;Verifica se esta no momento de Limpar o Dicionario
  mov ax,[AND_STR]		;Valor para ANDs
  cmp bp,ax
  jne INSARRAYGC
    ;Eh permitido Limpa Dicionario?
    mov al,[C_DICTIO]
	or al,0x00
	jz INSARRAYGC
	  ;Testa para ver se nao vai querer aumentar o numero de bits
      mov al,[G_BITS]
  	  or al,0x00
	  jz INSARRAYCCLEANC
	  mov ax,[CODSZ]
	  cmp ax,0x0010
	  jb INSARRAYGC
	  INSARRAYCCLEANC:
	  
	  ;Limpa ARRAY
	  mov bp,0x00FF ;Posiciona como se so os ASCII estivessem no ARRAY
      mov ax,[CN_DICTIO]
      inc ax
      mov [CN_DICTIO],ax
	  ;Sai como se tivesse inserido
	  clc
	  jmp INSARRAYE
    INSARRAYCCLEAN:
  INSARRAYGC:
  
  ;Checa se Ainda Tem Posicao do Dicionario 
  mov ax,[AND_STR]		;Valor para ANDs
  cmp ax,bp
  jne INSARRAYC
    ;Aumenta Quantidade de Bits
    mov al,[G_BITS]
  	or al,0x00
	jz INSARRAYCGB
	  ;Numero de Bits
	  mov ax,[CODSZ]
	  cmp ax,0x0010
	  je INSARRAYCGB		;Nao da Para aumentar
	  ;call fputcclean ;por debug para erro 1
	  ;call pause
	  inc ax
	  mov [CODSZ],ax
	  ;AND_STR
      mov ax,[AND_STR]		;Valor para ANDs
	  shl ax,1
	  or ax,0x0001
	  mov [AND_STR],ax
	  ;Insere
      jmp INSARRAYC
	INSARRAYCGB:
	
    dec bp              ;Marca BP antigo
    stc					;Marca de Evento na INSHASH
    jmp INSARRAYE		;Finaliza Funcao
  INSARRAYC:
  
  ;Calcula Posicao na Memoria e seta em ES:DI
  call CALCPOSARRAY
  
  ;Insere na Memoria
  mov [es:di],cx
  mov ax,0x0002
  call ADDDIARRAY
  mov [es:di],dl
  
  ;Sucesso
  clc
  
  INSARRAYE:
  pop di
  pop es
  pop dx
  pop cx
  pop bx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Determinacao do Char 0 de uma String presente no ARRAY
;Descricao:
;   Retorna o Char Inicial da String dada presente ao dicionario
;Requer:
;   BX com codigo da String
;Retorna:
;   BH = 0
;   BL = Char 0 
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STR0ARRAY:
  push bp
  push di
  push es
  
  ;Posicao inicial no ARRAY
  mov bp,bx
  
  STR0ARRAYL:
    ;Calcula Posicao na Memoria
	call CALCPOSARRAY
	
	;Verifica se eh uma "string" ASCII
	cmp bp,0x100
	jb STR0ARRAYE
	
	;Continua procurando a "Raiz"
	mov bp,[es:di]
	jmp STR0ARRAYL
	
  STR0ARRAYE:
  ;Anda na memoria
  push ax
  mov ax,0x0002
  call ADDDIARRAY
  pop ax
  ;Pega o Char 0
  xor bh,bh
  mov bl,[es:di]
  
  pop es
  pop di
  pop bp
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Impressao de uma String do Dicionario
;Descricao:
;   Imprime uma determinada string do dicionario armazenando
;     seus caracteres em uma pilha de bytes, saida da execucao
;     com mensagem de erro caso o tamanho da string seja maior
;      que FFFFh
;Requer:
;   BX com codigo da string
;Retorna:
;   -Nada-
;Modifica:
;   STACKOUT  Segmento de Pilha de Saida de Bytes
;   Arquivo de Saida
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PRINTSTRARRAY:
  push dx
  push bp
  push ax
  push cx
  push ds
  
  ;segmento de pilha de saida de bytes
  mov ax,stackout
  mov ds,ax
  
  ;Posicao de Topo da Pilha
  mov si,0xFFFF
  
  ;Contador de Bytes a serem escritos
  xor cx,cx
  
  ;Codigo de String Inicial
  mov bp,bx
  
  PRINTSTRARRAYL:
    ;Calcula Posicao
	call CALCPOSARRAY
	
	;Verifica Se nao eh um Char
	cmp bp,0x100
	jb PRINTSTRARRAYE
	
	;Pega proxima sub-string
	mov bp,[es:di]
    mov ax,0x0002
    call ADDDIARRAY
	
	;Pega Char da Posicao Atual
	mov dl,[es:di]
	
	;Empilha Char
	mov [ds:si],dl
	inc cx
	dec si
	
	;Verifica Se ainda ha posicao na pilha
	jnz PRINTSTRARRAYLNE
	  ;Mensagem de Erro
	  mov ah,0x09
	  mov dx,SS_FULL
	  int 0x21
	  ;Finaliza Programa
	  call ENDFILES
	  jmp END
	PRINTSTRARRAYLNE:
    
	jmp PRINTSTRARRAYL  ;Loop
	
  PRINTSTRARRAYE:
  ;Ler Char da "STR" ASCII
  mov ax,0x0002
  call ADDDIARRAY
  mov dl,[es:di]
  
  ;Empilha
  mov [ds:si],dl
  inc cx
  
  ;Imprime Pilha para Arquivo de Saida
  mov dx,si
  call fputs
  
  pop ds
  pop cx
  pop ax
  pop bp
  pop dx
  ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Calculo da Posicao de Memoria para ARRAY
;Descricao:
;   Calcula e seta ES:DI para uma determinada posicao da ARRAY
;Requer:
;   BP Posicao Desejada
;Retorna:
;   ES Segmento da posicao
;   DI Offset da posicao
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CALCPOSARRAY:
  push ax
  push dx
  
  ;Calcula Posicao
  mov ax,0x0003 ;3 bytes por estrutura do array
  mul bp
  ;Offset
  mov di,ax
  and di,0x000F  
  ;Deslocamento de Segmentos
  shr ax,4
  shl dx,12
  or dx,ax
  ;Base dos Segmentos de Array
  mov ax,array   
  add ax,dx
  ;Segmento
  mov es,ax     
  
  pop dx
  pop ax
  ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Incremento de ES:DI para ARRAY
;Descricao:
;   Incrementa DI com AX mantendo-o valido para a ARRAY,
;   Modificando ES caso necessario.
;Requer:
;   AX  Quantidade a se incrementar
;   DI  Offset valido para ARRAY
;   ES  Segmento Valido para ARRAY
;Retorna:
;   ES e DI - Incrementados para posicao correta
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ADDDIARRAY:
  push ax
  push dx
  ;Adiciona AX
  mov dx,ax   ;Passa AX para DX
  mov ax,es   ;Recebe Segmento
  add di,dx   ;Adiciona
  ;Testa Carry
  jnc ADDDIARRAYOK1
    ;Adiciona referente ao carry 
    add ax,0x1000
  ADDDIARRAYOK1:
  ;Verifica Deslocamento
  cmp di,0x0010
  jb ADDDIARRAYOK2
    ;Passa Deslocamento para Segmento
    mov dx,di
	and di,0x000F
	shr dx,4
	add ax,dx
  ADDDIARRAYOK2:
  ;Verifica Segmento
  mov dx,arrayend
  cmp ax,dx
  jb ADDDIARRAYOK3
    ;Volta ao Inicio caso tenha chegado ao final
    mov ax,array
  ADDDIARRAYOK3:
  ;Salva Segmento
  mov es,ax
  
  pop dx
  pop ax
  ret
;==============================================================================
;==============================================================================
;  Funcoes de HASH
;==============================================================================
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Limpeza da HASH
;Descricao:
;   Limpa o Primeiro Campo de todas Posicoes do HASH
;Requer:
;   -Nada-
;Retorna:
;   -Nada-
;Modifica:
;   Primeiro Campo de Todas Posicoes da HASH
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CLEANHASH:
  push ax
  push di
  push dx
  push si

  ;Pega Segmento Inicial
  mov ax,hash
  mov es,ax
  
  ;Limpa Registradores
  xor dx,dx       ;Valor Nulo
  xor di,di       ;Offset
  xor si,si       ;Contador
  
  mov ax,0x0005   ;Valor dos "Passos" na memoria, uma vez que so precisa ser limpo o primeiro campo

  CLEANHL:
    ;Move Valor nulo Para Primeiro Campo
    mov [es:di],dx
	;Anda
    call ADDDIHASH
	;Conta
    dec si
    jnz CLEANHL
  
  ;Ultimo Valor Inserido como ASCII
  mov ax,0x00FF
  mov [LAST_VLE_INS],ax
  
  ;Conta Numero de Limpezas
  mov ax,[CN_DICTIO]
  inc ax
  mov [CN_DICTIO],ax

  pop si
  pop dx
  pop di
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Espalhamento da HASH
;Descricao:
;   Calcula posicao na HASH para uma STR+CHAR e posiciona
;Requer:
;   CX com Codigo da STR
;   DL com Codigo do CHAR
;Retorna:
;   SI Valor da HASH
;   ES Segmento da Posicao
;   DI OffSet da Posicao
;Modifica:
;   Registradores em <Retorna>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FHASH:
  push ax
  push cx
  push dx
  
  ;Contas de Melhor Rendimento
  add cl,dl
  dec cl
  sub ch,dl
  inc ch
  
  ;Contas Sugeridas
  ;xor dh,dh
  ;shl dx,4
  ;xor cx,dx
  
  ;Valor da HASH
  mov si,cx
  
  ;Forcar Colisao
  ;mov cx,0xFFFF
  ;xor cx,cx
  
  ;Valor da HASH na Memoria (multiplica por 5(tamanho das "structs"))
  mov ax,cx
  mov cx,0x0005 ;5 bytes por estrutura da hash
  mul cx
  ;Offset
  mov di,ax     
  and di,0x000F
  ;Deslocamento de Segmentos
  shr ax,4
  shl dx,12
  or dx,ax
  ;Segmento
  mov ax,hash   ;Base dos Segmentos
  add ax,dx
  mov es,ax     ;Segmento
  
  pop dx
  pop cx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Insercao na HASH de um COD+STR+CHAR
;Descricao:
;   Insere STR+CHAR no Dicionario dando ao conjunto um codigo
;    de diconario, o qual sera adicionado junto com STR+CHAR na
;    na HASH, se a STR+CHAR ja nao estiver no dicionario.
;Requer:
;   CX Codigo de dicionario da String
;   DL Char
;Retorna:
;   CF=0 Se consegui Inserir, CF=1 caso contrario
;   BP=Codigo do resultado da Operacao:
;        0 - Sucesso
;        1 - STR+CHAR ja existente no Dicionario
;        2 - Erro, Dicionario lotado
;        FFFF - Erro, HASH Lotada
;   SI=Codigo de Dicionario da STR+CHAR, se inserida ou ja existente
;Modifica:
;   LAST_VLE_HASH (Ultimo Codigo de Dicionario Inserido)
;   HASH_TMP          (Variavel Temporaria Interna da Funcao)
;   COL_N e COL_NH(Numero de Colisoes na HASH em Duas Words)
;
;   Alterada se aumento de numero de bits de codigo permitido e necessario:
;           CODSZ                (Numero de Bits do Codigo)
;           AND_STR            (Valor de AND limitador de Codigos)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INSHASH:
  push ax
  push bx
  push cx
  push dx
  push di
  
INSHASHR:
  mov bx,[LAST_VLE_INS]	;Proximo Valor para um item no Dicionario
  inc bx
  
  call FHASH			;Calcula Valor de HASH
  
  mov bp,si
  INSHASHL:
    ;Pega Valores Atuais da HASH para a posicao
    mov ax,[es:di]
	
	;Verifica se esta Livre
    or ax,0x0000
	jz INSHASHINS
	
	;Pega STR+CHAR da HASH
	mov [HASH_TMP],ax		;Salva Codigo de Dicionario da Posicao
	mov ax,0x02
	call ADDDIHASH
    mov ax,[es:di]			;Pega STR
	push ax
	mov ax,0x02
	call ADDDIHASH
	inc si
    mov dh,[es:di]			;Pega CHAR
	mov ax,0x01
	call ADDDIHASH
	pop ax
	
	;Verifica se eh igual ao q se quer inserir
    cmp ax,cx              ;Compara STR
    jne INSHASHLCONT
    cmp dh,dl              ;Compacara Char
    jne INSHASHLCONT
	  ;Codigo de Erro
	  mov bp,0x0001
	  ;Valor Salvo na Temp
	  mov si,[HASH_TMP]
	  ;Seta Carry e Finaliza Funcao
	  stc
	  jmp INSHASHE
    INSHASHLCONT:
	
    ;Verifica se ja deu uma volta inteira na HASH
    cmp si,bp
    jne INSHASHCONT2
      mov bp,0xFFFF		;Valor de Erro para HASH Cheia
      stc				;Marca de Evento na INSHASH
      jmp INSHASHE		;Finaliza Funcao
	INSHASHCONT2:
	
	;Loop
	jmp INSHASHL
  
  ;Insere
  INSHASHINS:
  
  ;Verifica se esta no momento de Limpar o Dicionario
  mov ax,[AND_STR]		;Valor para ANDs
  cmp bx,ax
  jne INSHASHGC
    ;Limpa Dicionario
    mov cl,[C_DICTIO]
	or cl,0x00
	jz INSHASHGC
	  ;Testa para ver se nao vai querer aumentar o numero de bits
      mov al,[G_BITS]
  	  or al,0x00
	  jz INSHASHCCLEANC
	  mov ax,[CODSZ]
	  cmp ax,0x0010
	  jb INSHASHGC
	  INSHASHCCLEANC:
	  
	  ;Limpa ARRAY
	  call CLEANHASH
	  clc
	  jmp INSHASHE
  INSHASHGC:
  
  ;Checa se Ainda Tem Posicao do Dicionario
  mov ax,[AND_STR]		;Valor para ANDs
  and ax,bx
  jnz INSHASHC
    ;Aumenta Quantidade de Bits
    mov al,[G_BITS]
	or al,0x00
	jz INSHASHCGB
	  ;Numero de Bits
	  mov ax,[CODSZ]
	  cmp ax,0x0010
	  je INSHASHCGB		;Nao da Para aumentar
	  inc ax
	  mov [CODSZ],ax
	  ;AND_STR
      mov ax,[AND_STR]		;Valor para ANDs
	  shl ax,1
	  or ax,0x0001
	  mov [AND_STR],ax
	  ;Insere
	  jmp INSHASHC
    INSHASHCGB:
	
    mov bp,0x0002		;Valor de Erro para Dicionario Cheio
    stc					;Marca de Evento na INSHASH
    jmp INSHASHE		;Finaliza Funcao
  INSHASHC:
  
  ;Coloca Valores na HASH
  mov ax,0x02
  mov [es:di],bx		;Codigo do Dicionario 
  mov [LAST_VLE_INS],bx;Salva Indice
  call ADDDIHASH
  mov [es:di],cx		;STR
  call ADDDIHASH
  mov [es:di],dl		;CHAR
  
  ;Verifica Colisao e as conta 
  cmp si,bp
  je INSHASHINSC
    mov di,[COL_N]
    inc di
    mov [COL_N],di
    jnz INSHASHINSC
      mov di,[COL_NH]
      inc di
      mov [COL_NH],di
  
  INSHASHINSC:
  ;Move o Codigo do dicionario para SI
  mov si,bx
  
  ;Zera BP
  xor bp,bp
  
  ;Seta CF
  clc
  
  ;Finaliza
  INSHASHE:
  pop di
  pop dx
  pop cx
  pop bx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Incremento de ES:DI para HASH
;Descricao:
;   Incrementa DI (e ES) com AX deixando-os
;    prontos para a HASH
;Requer:
;   ES e DI configurados para HASH
;   AX Quantidade de Incremento para DI
;Retorna:
;   ES e DI incrementados e configurados para HASH
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ADDDIHASH:
  push ax
  push dx
  ;Adiciona
  mov dx,ax         ;Salva Valor de Incremento
  mov ax,es         ;Pega Segmento
  add di,dx         ;Adiciona
  ;Verifica Carry
  jnc ADDDIHASHOK1
    ;Adiciona Referente Carry no segmento
    add ax,0x1000
  ADDDIHASHOK1:
  ;Verifica Offset
  cmp di,0x0010
  jb ADDDIHASHOK2
    ;Passa parte do offset para segmento
    mov dx,di
	and di,0x000F
	shr dx,4
	add ax,dx
  ADDDIHASHOK2:
  ;Verifica Segmetno
  mov dx,hashend
  cmp ax,dx
  jb ADDDIHASHOK3
    ;Da Loop caso necessario
    mov ax,hash
  ADDDIHASHOK3:
  ;Salva Segmento
  mov es,ax
  
  pop dx
  pop ax
  ret
;==============================================================================
;==============================================================================
;  Funcoes de Entrada/Saida
;==============================================================================
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Leitura de N Bits do Arquivo de Entrada
;Descricao:
;   Retorna Bits na quantidade desejada
;Requer:
;   AL Numero de bits a serem Lidos
;Retorna:
;   AH Numero de bits no Buffer
;   AL Numero de bits Lidos
;   DX Bits Lidos
;   CF=0 em caso de sucesso, CF=1 caso contrario
;Modifica:
;   BUF_IN            (Buffer de Entrada para Tratamento em bits)
;                           (Bits Validos Posicionados nos bits menos significativos)
;   LEN_BUF_IN    (Numero de Bits Validos em BUF_IN)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fread:
  push bx
  push cx
  push di
  
  ; Declaracoes Iniciais
  mov bh,[LEN_BUF_IN]   ;BH Tamanho do Buffer
  mov bl,al				;BL quantos faltam LER
  xor al,al             ;AL Quantos Ja foram Lidos
  xor cx,cx             ;CX Bits Lidos
  mov dx,[BUF_IN]       ;DX Buffer
  
  freadp:
  ;Passagem do Buffer para Lidos
  
  ;Proximo Buffer
  mov di,dx
  
  ;Shifta Para Direita par limpar os que naum serao usados
  cmp bh,bl
  jb freadp1
    ;Apaga bits que naum serao usados
    mov ah,bh
    sub ah,bl
	call SHIFTR
	
    ;Limpa Buffer Usado
	sub ah,0x10
	neg ah
	xchg dx,di
	call SHIFTL
	call SHIFTR
	xchg dx,di
	
	;Calcula Valores
	sub ah,0x10   ;Quanto foi Lido
	neg ah
	add al,bh
	sub al,ah
	
	xor bl,bl     ;Quantos Faltam Ler
	
	mov bh,ah     ;Tamanho do buffer
	
	jmp freadpl
  freadp1:
  
  ;Shifta para Esquerda Para Posicionar
  cmp bh,bl
  jge freadp2
  
    mov ah,bl
    sub ah,bh
	call SHIFTL
	
	add al,bh     ;Quanto foi Lido
	
	mov bl,ah     ;Quantos Faltam Ler
	
	xor bh,bh     ;Tamanho do buffer
	
	xor di,di     ;Novo buffer
  freadp2:
  freadpl:
  
  ;Manda Para Lidos
  or cx,dx
  
  mov dx,cx
  
  ;Coloca novo Buffer no local
  mov dx,di
  
  ;Checagem de Mais bits Necessarios 
  or bl,0x00
  jz freade
    xor dx,dx
	
	;Pega mais um char
	call fgetc
	;Verifica Leitura
	jnc freadgb
	  ;Naum conseguiu ler
	  ;Move Resultado Parcial para Posicao
	  mov dx,cx
	  ;Posiona Bits
	  mov ah,bl
	  call SHIFTR
	  ;Retorna
      pop di
      pop cx
      pop bx
	  stc
      ret
	freadgb:
	
	add bh,0x08     ;Tamanho do buffer
	
	jmp freadp
	
  freade:
  ;Finalizacao
  mov [LEN_BUF_IN],ah   ;Tamanho do Buffer
  mov [BUF_IN],dx       ;Buffer
  mov dx,cx             ;Resultado

  pop di
  pop cx
  pop bx
  clc
  ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Finalizacao da Escrita Binaria no Arquivo de Saida
;Descricao:
;   Escreve Bits Restantes no Buffer de Saida, completando bytes se necessario
;Requer:
;   -Nada-
;Retorna:
;   -Nada-
;Modifica:
;   BUF_OUT           (Buffer de Entrada para Tratamento em bits)
;                             (Bits Validos Posicionados nos bits mais significativos)
;   LEN_BUF_OUT   (Numero de Bits Validos em BUF_IN)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fwriteclean:
	push ax
	push dx
	
	;Verifica se tem algo no Buffer
	mov ah,[LEN_BUF_OUT]   ;Tamanho do Buffer
	or ah,0x000
	jz fwritecleanEND
	
	;Escreve o byte mais significativo
	mov dx,[BUF_OUT]
	ror dx,8
	call fputc
	
	;Ve se tem mais de um byte a escrever
	cmp ah,0x08
	jbe fwriteclean8
	  ;Escreve o Menos Significativo
	  shr dx,8
	  call fputc
	fwriteclean8:
	
	;Salva Modificacoes
	xor ax,ax
	mov [LEN_BUF_OUT],ah     ;Salva Numero de Bits
	mov [BUF_OUT],ax         ;Salva Buffer
	fwritecleanEND:
	
	pop dx
	pop ax
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Escrita de N Bits do Arquivo de Saida
;Descricao:
;   Escreve Bits na quantidade desejada
;Requer:
;   AL Numero de bits a serem Escritos
;   DX Bits a Serem Impressos posicionados nos bits menos significativos
;Retorna:
;   -Nada-
;Modifica:
;   BUF_OUT           (Buffer de Entrada para Tratamento em bits)
;                             (Bits Validos Posicionados nos bits mais significativos)
;   LEN_BUF_OUT   (Numero de Bits Validos em BUF_IN)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fwrite:
  push dx
  push ds
  push di
  push si
  push bx
  push ax
  
  mov ah,[LEN_BUF_OUT]     ;Tamanho do Buffer
  mov si,[BUF_OUT]         ;Buffer
  mov di,dx                ;Backup dos novos Bits
  
  mov bl,al
  add bl,ah                ;Numero Total de Bits sendo processados
  cmp bl,0x10
  jb ADDBUF_fwrite         ;Tem 16 bits a escrever?	
    
    sub ah,0x10              ;Qtd de Bits livres
    add ah,al                ;Valor a ser Shiftado dos valores novos
    
    call SHIFTR              ;shr dx,ah  Shiftando para utilizar bits necessarios
    or si,dx                 ;Adicionando para escrever
    
    ;Escrita
    mov dx,si
    ror dx,8
    call fputc
    shr dx,8
    call fputc
    
    sub bl,0x10              ;Calcula numero Faltantes de Bits para uma Proxima
    xor si,si                ;Limpa Buffer
    mov dx,di                ;Recupera Bits Recebidos
    
  ADDBUF_fwrite:
  mov ah,0x10
  sub ah,bl                ;Total de Bits faltantes para escrever
  
  call SHIFTL              ;shl dx,ah     Shifta Novos bits
  or si,dx                 ;Acrescenta no Buffer
  
  END_fwrite:
  mov ah,bl                ;Numero de Bits no Buffer
  mov [LEN_BUF_OUT],ah     ;Salva Numero de Bits
  mov [BUF_OUT],si         ;Salva Buffer
  
  pop ax
  pop bx
  pop si
  pop di
  pop ds
  pop dx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao Leitura de Char do Arquivo de Entrada
;Descricao:
;   Le um char do arquivo de entrada
;Requer:
;   -Nada-
;Retorna:
;   DL Char Lido
;   CF=0 em caso de sucesso, CF=1 caso contrario
;Modifica:
;   Segmento de Buffer de Entrada
;   PTR_BUFFER_IN (Offset atual no segmento de buffer de entrada)
;   LEN_BUFFER_IN(Quantidade Char Validos no Segmento de Buffer de Entrada)
;   LEN_B_IN e LEN_B_INH (Tamanho do Arquivo de Entrada em 2 words)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fgetc:
  push es
  push ax
  push di
  push ds
  
  ;Segmento de Dados
  mov ax,data
  mov ds,ax
  
  ;Vai para segmento de buffer
  mov ax,buffer_in
  mov es,ax
  
  ;Pega ponteiro da primeira posicao do buffer
  mov di,[PTR_BUFFER_IN]
  
  ;Pega Tamanho do Buffer
  mov ax,[LEN_BUFFER_IN]
  
  ;Aavalia Tamanho para Ver se possui algo
  or ax,0x000
  jnz fgetcb
    push cx
	push dx
	push bx
	
	;Le para o Buffer FFFFh
    mov bx,[FL_HANDLE1]
	push ds
    mov cx,0xFFFF
    xor dx,dx
	mov ax,buffer_in
	mov ds,ax
    mov ah,0x3f
    int 0x21
	pop ds
	
	;Ajuste de Ponteiro
	xor di,di
	
	;Contagem de Caracteres Lidos
	mov cx,ax
	mov dx,[LEN_B_IN]
	mov bx,[LEN_B_INH]
	add cx,dx
	adc bx,di
	mov [LEN_B_IN],cx
	mov [LEN_B_INH],bx
	
	pop bx
	pop dx
	pop cx
	
	;Avalia se a Leitura Conseguiu alguma coisa
	or ax,ax
	jnz fgetcb
	  ;Define Retorno de Erro e sai da funcao
	  xor dl,dl
	  stc
	  jmp fgetce
  fgetcb:
  ;Recebe Char do Buffer
  mov dl,[es:di]
  
  ;Atualiza Variaveis
  inc di
  mov [PTR_BUFFER_IN],di
  dec ax
  mov [LEN_BUFFER_IN],ax
  
  ;Retorna com Sucesso
  clc
  
  fgetce:
  pop ds
  pop di
  pop ax
  pop es
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Escrita de um Char no Arquivo de Saida
;Descricao:
;   Escrita de um char no Arquivo de Saida
;Requer:
;   DL Char a Ser impresso
;Retorna:
;   -Nada-
;Modifica:
;   Segmento de Buffer de Saida
;   PTR_BUFFER_OUT (Offset atual no segmento de buffer de saida)
;   LEN_BUFFER_OUT(Quantidade Char Validos no Segmento de Buffer de Saida)
;   LEN_B_OUT e LEN_B_OUTH (Tamanho do Arquivo de Saida em 2 words)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fputc:
  push es
  push ax
  push di
  push ds
  
  ;Segmentos de Dados
  mov ax,data
  mov ds,ax
  
  ;Segmento de Buffer
  mov ax,buffer_out
  mov es,ax
  
  ;Ponteiro da Proxima posicao do buffer
  mov di,[PTR_BUFFER_OUT]
  
  ;Tamanho do Buffer
  mov ax,[LEN_BUFFER_OUT]
  
  ;Verifica se cheio Imprime
  cmp ax,0xFFFF
  jne fputcb
    push cx
    push dx
    push bx
	push si
    
	xor dh,dh
	mov dl,[V_OFL] ;Imprimir Arquivo Descompactado na Tela
	mov si,dx
	
	;Prepara para Imprimir o que tem no buffer para arquivo
    mov bx,[FL_HANDLE2]
    push ds
    mov cx,ax
    mov ax,buffer_out
    mov ds,ax
	
	;Imprime o que tem no buffer para arquivo
    xor dx,dx
    mov ah,0x40
    int 0x21
	
	;Imprimir na Tela?
	or si,0x00
	jz fputcbvf
	  mov [di],byte 0x24
      mov ah,0x09
      int 0x21
	fputcbvf:
	
	;Recupera Segmento
    pop ds
    
	;Seta Ponteiro
    xor di,di
    
    ;Contagem de Caracteres Escritos
    mov dx,[LEN_B_OUT]
    mov bx,[LEN_B_OUTH]
    add cx,dx
    adc bx,di
    mov [LEN_B_OUT],cx
    mov [LEN_B_OUTH],bx
    
	;Quantidade de itens no Buffer
    xor ax,ax
    
	pop si
    pop bx
    pop dx
    pop cx
	
  fputcb:
  ;Coloca Char no Buffer
  mov [es:di],dl
  
  ;Atualiza Variaveis
  inc di
  mov [PTR_BUFFER_OUT],di
  inc ax
  mov [LEN_BUFFER_OUT],ax
  
  pop ds
  pop di
  pop ax
  pop es
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Impressao de Strings
;Descricao:
;   Imprime um String dada, usando fputc
;Requer:
;   DS Segmento onde esta a String
;   DX Offset do primeiro char
;   CX Quantidade de Caracteres a serem escritos
;Retorna:
;   -Nada-
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fputs:
  push cx
  push dx
  push di
  ;Move posicao para DI
  mov di,dx
  ;Loop
  fputsl:
    ;Pega Char da String
    mov dl,[di]
	;Imprime
    call fputc
	;Anda
    inc di
	;Conta
    dec cx
    jnz fputsl
	
  pop di
  pop dx
  pop cx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Finalizacao da Escrita no Arquivo de Saida
;Descricao:
;   Escreve Todo Buffer de Saida  no Arquivo
;Requer:
;   -nada-
;Retorna:
;   -Nada-
;Modifica:
;   Segmento de Buffer de Saida
;   PTR_BUFFER_OUT (Offset atual no segmento de buffer de saida)
;   LEN_BUFFER_OUT(Quantidade Char Validos no Segmento de Buffer de Saida)
;   LEN_B_OUT e LEN_B_OUTH (Tamanho do Arquivo de Saida em 2 words)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fputcclean:
  push es
  push ax
  push di
  push ds
  
  ;Segmento de Dados
  mov ax,data
  mov ds,ax
  
  ;Tamanho do Buffer
  mov ax,[LEN_BUFFER_OUT]
  ;Verifica se ainda tem algo nele
  or ax,0x000
  jz fputccb
    push cx
	push dx
	push bx
	push si
	
	xor dh,dh
	mov dl,[V_OFL]   ;Se vai imprimir na Tela
	mov si,dx
	
	;Escreve o que tiver nele no Arquivo
    mov bx,[FL_HANDLE2]
    mov cx,ax
    xor dx,dx
	push ds
	mov ax,buffer_out
	mov ds,ax
    mov ah,0x40
    int 0x21
	
	;Imprimir na Tela?
	or si,0x00
	jz fputccbvf
	  mov [di],byte 0x24
      mov ah,0x09
      int 0x21
	fputccbvf:
	
	pop ds
	
	;Atualiza Ponteiro
	xor di,di
	
	;Contagem de Caracteres Escritos
	mov dx,[LEN_B_OUT]
	mov bx,[LEN_B_OUTH]
	add cx,dx
	adc bx,di
	mov [LEN_B_OUT],cx
	mov [LEN_B_OUTH],bx
	
	pop si
	pop bx
	pop dx
	pop cx
	
	;Novo Tamanho do Buffer
    xor ax,ax
	
	;Salva Variaveis
    mov [PTR_BUFFER_OUT],ax
    mov [LEN_BUFFER_OUT],ax
  fputccb:
  
  pop ds
  pop di
  pop ax
  pop es
ret
;==============================================================================
;==============================================================================
;  Funcoes de SHIFT
;==============================================================================
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que desloca os bits de dx para a direita para o numero de bits representado por ah 
;Descricao:
; Desloca para a direita ah bits de dx
;Requer:
;  AH = extensao do deslocamento
;  DX = objeto da acao
;Retorna:
;   dx descolado ah bits para a direita
;Modifica:
; dx, ah
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SHIFTR:
  push ax
  or ah,0x00	; testa se ah eh igual a zero
  jz SHIFTRE
  SHRRL:		; enquanto ah nao for zero desloca dx em 1 bit para a direita
  shr dx,1	
  dec ah
  jnz SHRRL
  SHIFTRE:		; se ah for zero
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que desloca os bits de dx para a esquerda para o numero de bits representado por ah
;Descricao:
; Desloca para a esquerda ah bits de dx
;Requer:
;  AH = extensao do deslocamento
;  DX = objeto da acao
;Retorna:
;   dx descolado ah bits para a esquerda
;Modifica:
; dx, ah
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;shift dx, ah para a esquerda
SHIFTL:
  push ax
  or ah,0x00		; testa se ah eh zero
  jz SHIFTLE	
  SHRLL:			; enquanto ah nao for zero, desloca dx em 1 bit para a esquerda
  shl dx,1
  dec ah
  jnz SHRLL			
  SHIFTLE:			; se ah for zero
  pop ax
  ret
;==============================================================================
;  Funcoes Impressoes de Informacoes Opcionais
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que exibe o numero de colisoes ocorridas durante a contrucao do dicionario
;Descricao:
;   Imprime na saida padrao o numero de colisoes ocorridas na hashtable
;Requer:
; TOT_COL, SHOWCOL, COL_NH, COL_N
;Retorna:
;   -Nada-
;Modifica:
;  -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
showcolnumber:
  push ax
  push cx
  push dx
  
  xor ch,ch
  mov cl,[SHOWCOL]
  jcxz showcolnumberz 
  
  mov ah,0x09
  mov dx,TOT_COL		
  int 0x21
  
  mov dx,[COL_NH]
  call printHexn
	
  mov dx,[COL_N]
  call printHex
  
  showcolnumberz:
  pop dx
  pop cx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que exibe o dicionario na saida padrao
;Descricao:
;   Imprime no console o dicionario utilizado para des/codificacao
;Requer:
; S_DICIO, LAST_VLE_INS, C_DICIO, CDICIO_QTD, CN_DICIO
;Retorna:
;   -Nada-
;Modifica:
;   -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
showdicio:
  push ax
  push cx
  push dx
  
  xor ch,ch
  mov cl,[S_DICIO]
  jcxz showdicioz
  
    mov ah,0x09
    mov dx,DICTIO_QTD
    int 0x21
  
    mov dx,[LAST_VLE_INS]
    inc dx
    call printHex
  
    mov cl,[C_DICTIO]
    jcxz showdicioz
  
    mov ah,0x09
    mov dx,CDICTIO_QTD
    int 0x21
  
    mov dx,[CN_DICTIO]
    call printHex
  
  showdicioz:
  pop dx
  pop cx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que converte uma representacao binaria para a codificacao Hexadecimal
;Descricao:
;  Converte valores binarios no formato hexadecimal
;Requer:
; DX = codigo a ser impresso
;Retorna:
;  -Nada-
;Modifica:
; -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
printHexn:
  push bx
  push dx
  push ax
  
  mov bx,dx
  mov ah,0x02
  
  mov dx,bx
  ;shl dx,0
  shr dx,12
  add dx,0x30
  cmp dx,0x39
  jbe scoln1
  add dx,0x07
  scoln1:
  int 0x21
  
  mov dx,bx
  shl dx,4
  shr dx,12
  add dx,0x30
  cmp dx,0x39
  jbe scoln2
  add dx,0x07
  scoln2:
  int 0x21
  
  mov dx,bx
  shl dx,8
  shr dx,12
  add dx,0x30
  cmp dx,0x39
  jbe scoln3
  add dx,0x07
  scoln3:
  int 0x21
  
  mov dx,bx
  shl dx,12
  shr dx,12
  add dx,0x30
  cmp dx,0x39
  jbe scoln4
  add dx,0x07
  scoln4:
  int 0x21
  
  pop ax
  pop dx
  pop bx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Impressao em numeracao Hexadecimal
;Descricao:
;  Converte e imprime valores binarios no formato hexadecimal
;Requer:
; DX = codigo a ser impresso
;Retorna:
;  -Nada-
;Modifica:
; -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
printHex:
  push dx
  push ax
  
  call printHexn
  
  mov ah,0x02
  mov dl,0x0A
  int 0x21
  
  pop ax
  pop dx
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que exibe os tamanhos dos arquivos de entrada e saida apos des/compactacao
;Descricao:
;   Imprime na saida padrao o tamanho em bytes dos arquivos entrada e saida apos des/compactacao
;Requer:
;   SHOWSZ, LEN_B_INH, LEN_B_IN, SZ_FLOUT, LEN_B_OUTH, LEN_B_OUT
;Retorna:
;   -Nada-
;Modifica:
;   -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
showsizes:
  push ax
  push cx
  push dx
  
  xor ch,ch
  mov cl,[SHOWSZ]
  jcxz showsizesz
    mov ah,0x09
    mov dx,SZ_FLIN
	int 0x21
	
    mov dx,[LEN_B_INH]
	call printHexn
	
    mov dx,[LEN_B_IN]
	call printHex
	
    mov dx,SZ_FLOUT
	int 0x21
	
    mov dx,[LEN_B_OUTH]
	call printHexn
	
    mov dx,[LEN_B_OUT]
	call printHex
  showsizesz:
  pop dx
  pop cx
  pop ax
  ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que calcula e exibe a taxa de compressao do processo 
;Descricao:
; Obtem TC= 1-TA/TO
;Requer:
; SHOWSZ, LEN_B_INH, LEN_B_IN, SZ_FLOUT, LEN_B_OUTH, LEN_B_OUT
;Retorna:
;   -Nada-
;Modifica:
;   -Nada-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
showcompact:
  push ax
  push cx
  push dx
  
  xor ch,ch
  mov cl,[SHOWSZ]
  jcxz showcompz
    mov ah,0x09
    mov dx,SZ_FLIN
	int 0x21
	
    mov dx,[LEN_B_INH]
	call printHexn
	
    mov dx,[LEN_B_IN]
	call printHex
	
    mov dx,SZ_FLOUT
	int 0x21
	
    mov dx,[LEN_B_OUTH]
	call printHexn
	
    mov dx,[LEN_B_OUT]
	call printHex
	
	;CALCULOS da Taxa de Compactação
  showcompz:
  pop dx
  pop cx
  pop ax
  ret
;==============================================================================
;  Funcoes Diversas
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Copia de Strings por Tamanho e Quebra por Espacos
;Descricao:
; Copia ds:si para es:di, acrecentando no final o caracter em AH
; ate um espaco na fonte ou ate zerar CX
;Requer:
;   AL retornado por interrupcao de abertura
;   DX setado com end da string do nome do arquivo no qual
;     houve o erro, padrao igual aa interrupcao de abertura
;Retorna:
;   AX quantidade de bytes copiados
;Modifica:
;   CX,SI,DI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STRCPY:
  push bx
  ;Copia Caracter de Fim de String
  mov bh,ah
  ;Zera AX
  xor ax,ax
  ;Testa Comprimento
  jcxz STRCPE
  ;Loop de copia de string
  STRCP:
    ;Pega Char
    mov bl,[es:si]
	;Avalia se nao eh espaco
    cmp bl,0x20
    je STRCPE
	;Salva no destino
    mov [ds:di],bl
	;Anda
	inc ax
    inc si
	;conta
    dec cx
    jcxz STRCPE
	;Anda
    inc di
    jmp STRCP
  STRCPE:
  
  ;Seta Caracter Final da String
  mov [ds:di],bh
  pop bx
  
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao que interrompe a execucao enquanto nao le um caracter da entrada
;Descricao:
; Pausa a execucao ate um caracter ser lido da entrada padrao
;Requer:
; -Nada
;Retorna:
;   -Nada-Finaliza
;Modifica:
; -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pause:
  push ax
  push dx
  mov ah,0x02
  mov dl,'!'
  int 0x21
  mov ah,0x01
  int 0x21
  pop dx
  pop ax
  ret
;==============================================================================
;  Fim de Programa
;==============================================================================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Funcao de Finalizacao e retorno do controle ao DOS
;Descricao:
;   Finaliza a execucao do programa
;Requer:
;   -Nada
;Retorna:
;   -Nada-Finaliza
;Modifica:
;   -Nada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Finaliza Execucao do Programa Retornando ao DOS
END:;------------------------------------------------------------------------
  mov  ah, 0x4C             ; volta controle ao DOS
  int  0x21

align 16
SEGMENT data; segmento de dados ----------------------------------------------
;Help
HELP_M:
db "===========================================================================",0x0D,0x0A
db "Programa de Compactacao LZW de ate 16 bits",0x0D,0x0A
db "Execucao: LZW -<opcoes> <Arquivo de Entrada> <Arquivo de Saida>",0x0D,0x0A,0x0A
db "Opcoes Validas:",0x0D,0x0A
db "# - Numero de Bits a ser usado:  9 10 11 12 13 14 15 16",0x0D,0x0A
db "                    Valor de #:  9  0  1  2  3  4  5  6",0x0D,0x0A
db "H - Ajuda (Esta Mesma)",0x0D,0x0A
db "E - Compacta",0x0D,0x0A
db "X - Descompacta",0x0D,0x0A,0x0A
db "F - Forcar criacao do Arquivo de Saida",0x0D,0x0A
db "S - Mostrar Tamanhos dos Arquivos",0x0D,0x0A
db "C - Mostrar Numero de Colisoes na HASH de Compactacao",0x0D,0x0A
db "D - Mostrar Numero de Itens no Dicionario",0x0D,0x0A
db "Q - Limpar Dicionario quando este estiver lotado",0x0D,0x0A
db "G - Numero de Bits Crescente Comecando de '#' ate 16",0x0D,0x0A,0x0A
db "V - Exibe Arquivo Descompactado na Tela durante Descompactacao",0x0D,0x0A
db "Opcoes de Compactibilidade com outros compactadores:",0x0D,0x0A
db "T - Sem Marcacao 'LZW' no Compactado ",0x0D,0x0A
db "Y - Sem Byte de Configuracao no Compactado",0x0D,0x0A
db 0x0A
db "Sugestao de Otimizacao da Compactacao:",0x0D,0x0A
db "LZW -E9GQ(F) <Arquivo de Entrada> <Arquivo de Saida>",0x0D,0x0A
db 0x24

;Mensagens de Erros
UD_FUCT: db "Undefined Function. Please use -e or -x",0x0D,0x24

WR_COMMD: db "Not Accepted Command",0x0D,0x24
FILE_NF: db "File not Found",0x0D,0x24
PATH_NF: db "Path not Found",0x0D,0x24
NHAN_AV: db "No handle available",0x0D,0x24
ACCE_DE: db "Access Denied",0x0D,0x24
MODE_IN: db "Open Mode Invalid",0x0D,0x24
ERROR_NR: db "Error Not Recognized",0x0D,0x24
CREAT_FL: db "Error on Create Output File",0x0D,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
IO_FL_NF: db "Input and Output Files Name not Found",0x0D,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
O_FL_NF: db "Output File Name not Found",0x0D,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
OPT_NF: db " : Option not Found",0x0D,0x0A,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
QTDE_BT: db " : Quantidade de Bits Invalida",0x0D,0x0A,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
FL_LZWN: db "Nao ha marcacao LZW no arquivo, o que parece nao ser um arquivo compactado, para forcar a descompactacao use a opcao T",0x0D,0x0A,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
BITC_NF: db "Nao ha Byte de Configuracao, favor especificar configuracao por linha de comando e usar opcao Y para descompactar",0x0D,0x0A,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
SS_FULL: db "String Stack is Full, bad file! Bye!!!",0x0D,0x0A,0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate

FL_EXIST: db "File Exist",0x0D,0x24

TOT_COL: db "Total Colision: ",0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
SZ_FLIN: db "Size of File IN:  ",0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
SZ_FLOUT: db "Size of File OUT: ",0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
DICTIO_QTD: db "Dictionary Size: ",0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate
CDICTIO_QTD: db "Dictionary Cleaned: ",0x24 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,,translate

;Opcoes de Execucao ( Em Geral: 0 Modo Padrao, 1 Modo Opcional)
MOD: db 0x00      ;1= compacta    2 = descompacta
CODSZ: db 0x0C    ;Tamanho dos Codigos
FORCE: db 0x01    ;Sobre-escreve arquivo de saida se existir 1-Sim 0-Nao
SHOWSZ: db 0x00   ;Exibir Tamanho de Arquivos 1-Sim 0-Nao
SHOWCOL: db 0x00  ;Exibir Numero de Colisoes 1-Sim 0-Nao
C_DICTIO: db 0x00 ;Limpar Dicionario quando cheio 1-Sim 0-Nao
G_BITS: db 0x00   ;Numero de Bits da Codificacao Crescente 1-sim 0-Nao
S_DICIO: db 0x00  ;Mostrar Tamanho do dicionario 1-Sim 0-Nao
B_CONF: db 0x00   ;Usar Byte de Configuracao 1-Nao 0-Sim
P_LZW: db 0x00    ;Usar Marcacao LZW no Arquivo compactado 1-Nao 0-Sim
V_OFL: db 0x00    ;Exibir Arquivo de Saida Durante Descompactacao 1-Sim 0-Nao

;Nome de Arquivo
FL_NAME1: resb 0x80      ;nome do arquivo 1 (entrada)
FL_HANDLE1: resb 0x02    ;file handle do arquivo 1
FL_NAME2: resb 0x80      ;nome do arquivo 2 (saida)
FL_HANDLE2: resb 0x02    ;file handle do arquivo 2

;Buffer STD Out
LEN_BUF_OUT: db 0x00     ;Numero de Bits Validos em BUF_OUT
BUF_OUT: resb 0x02       ;Buffer de Saida Binaria

;Buffer STD In
LEN_BUF_IN: db 0x00     ;Numero de Bits Validos em BUF_IN
BUF_IN: resb 0x02       ;Buffer de Entrada Binaria

;Segmentos de Buffer
LEN_BUFFER_IN: dw 0x0000  ;Tamanho do Segmento de Buffer de Entrada
PTR_BUFFER_IN: dw 0x0000  ;Ponteiro da Proxima Posicao Valida do Buffer de Entrada
LEN_BUFFER_OUT: dw 0x0000  ;Tamanho do Segmento de Buffer de Saida
PTR_BUFFER_OUT: dw 0x0000  ;Ponteiro da Proxima Posicao Valida do Buffer de Saida

;HASH/ARRAY/Dicionario
LAST_VLE_INS: dw 0x00FF  ;Salva ultima "STR" salva no caso ultimo ascii
CN_DICTIO: dw 0x0000     ;Numero de Limpezas do Dicionario
HASH_TMP: dw 0x0000      ;Varivavel Temporaria Usada na Insercao na Hash

;LZW
AND_STR: dw 0x0FFF  ;Valor de Validacao por AND do codigo de Dicionario

;Sobre o Arquivo compactado
LEN_FORMAT: db 0x03					;Numero de Bits de FORMAT para se escrever no inciio de arquivos
FORMAT: db "LZW"                    ;Formatacao do Arquivo de Saida

;Numero de Colisoes
COL_NH: dw 0x0000    ;Word mais significativa do Numero de Colisoes
COL_N: dw 0x0000     ;Word menos significativa do Numero de Colisoes

;Tamanhos de Arquivos
LEN_B_INH: dw 0x0000  ;Word mais significativa do tamanho do arquivo de entrada
LEN_B_IN: dw 0x0000   ;Word menos significativa do tamanho do arquivo de entrada
LEN_B_OUTH: dw 0x0000 ;Word mais significativa do tamanho do arquivo de saida
LEN_B_OUT: dw 0x0000  ;Word menos significativa do tamanho do arquivo de saida


align 16

; HASH
;Sistema de Segmentos para HASH
;struct [ --------------] [ --------------][-------]
;            DICIO Value        STR          CHAR
;                   16b                16b           8b
; ARRAY
;Sistema de Segmentos para ARRAY
;struct [ --------------][-------]
;                  STR          CHAR
;                   16b           8b
SEGMENT hash
SEGMENT array
SEGMENT database0
resb 0x10000
align 16
SEGMENT database1
resb 0x10000
align 16
SEGMENT database2
resb 0x10000
align 16
SEGMENT arrayend
SEGMENT database3
resb 0x10000
align 16
SEGMENT stackout
SEGMENT database4
resb 0x10000
align 16
SEGMENT hashend

;Buffer de Entrada
SEGMENT buffer_in  ;segmento de Buffer de entrada
resb 0x10000
align 16

;Buffer de Saida
SEGMENT buffer_out ;segmento de Buffer de saida
resb 0x10000
align 16

;Segmento de Pilha
SEGMENT stack stack        ; segmento de pilha
  RESB 0x200
stacktop:
